package znet

import (
	"errors"
	"fmt"
	"io"
	"net"
	"zinx/utils"
	"zinx/ziface"
)

type Connection struct {
	//当前conn属于哪个 server
	TcpServer ziface.IServer
	//当前连接 sock
	Conn *net.TCPConn

	//会话id
	ConnID uint32

	//状态
	isClosed bool

	//处理api
	MsgHandler ziface.IMsgHandle

	//告诉该连接已经退出/停止的channel
	ExitBuffChann chan bool

	//无缓冲，用于读写两个goroutine
	msgChan chan []byte
	//有缓冲
	msgBuffChan chan []byte

	// ================================
	//链接属性
	property map[string]interface{}
	//保护链接属性修改的锁
	propertyLock sync.RWMutex
}

//创建连接的方法
func NewConnection(server ziface.IServer, conn *net.TCPConn, connID uint32, msgHandler ziface.IMsgHandle) *Connection {
	c := &Connection{
		TcpServer:     server,
		Conn:          conn,
		ConnID:        connID,
		isClosed:      false,
		ExitBuffChann: make(chan bool, 1),
		MsgHandler:    msgHandler,
		msgChan:       make(chan []byte),
		msgBuffChan:   make(chan []byte, utils.GlobalObject.MaxMsgChanLen),
		property:      make(map[string]interface{}), //对链接属性map初始化
	}

	c.TcpServer.GetConnMgr().Add(c)

	return c
}

//处理conn读数据的goroutine
func (c *Connection) StartReader() {
	fmt.Println("Reader gorouting is running ")
	defer fmt.Println(c.RemoteAddr().String(), " conn reader exit!")
	defer c.Stop()

	for {
		//封包
		dp := NewDataPack()
		headData := make([]byte, dp.GetHeadLen())
		//取头部
		if _, err := io.ReadFull(c.Conn, headData); err != nil {
			fmt.Println("read msg head error ", err)
			break
		}
		//拆包
		msg, err := dp.Unpack(headData)
		if err != nil {
			fmt.Println("Unpack error ", err)
			break
		}
		//根据datalen读取data
		var data []byte
		if msg.GetDataLen() > 0 {
			data = make([]byte, msg.GetDataLen())
			if _, err := io.ReadFull(c.Conn, data); err != nil {
				fmt.Println("read msg data error ", err)
				break
			}
		}
		msg.SetData(data)
		//调用当前连接业务处理
		req := Request{
			conn: c,
			msg:  msg,
		}
		if utils.GlobalObject.WorkerPoolSize > 0 {
			c.MsgHandler.SendMsgToTaskQueue(&req)
		} else {
			go c.MsgHandler.DoMsgHandler(&req)
		}
	}
}

func (c *Connection) StartWriter() {
	defer fmt.Println(c.RemoteAddr().String(), " conn Writer exit!")
	for {
		select {
		case data, ok := <-c.msgChan:
			//有数据要写给客户端
			if ok {
				if _, err := c.Conn.Write(data); err != nil {
					fmt.Println("Send Data error:, ", err, " Conn Writer exit")
					return
				}
			} else {
				fmt.Println("msgChan is Closed")
				break
			}
		case data, ok := <-c.msgBuffChan:
			if ok {
				//有数据要写给客户端
				if _, err := c.Conn.Write(data); err != nil {
					fmt.Println("Send Buff Data error:, ", err, " Conn Writer exit")
					return
				}
			} else {
				fmt.Println("msgBuffChan is Closed")
				break
			}
		case <-c.ExitBuffChann:
			//conn已经关闭
			return
		}
	}
}

//启动连接
func (c *Connection) Start() {
	//开户处理连接读取到客户端数据之后的请求业务
	go c.StartReader()
	go c.StartWriter()

	c.TcpServer.CallOnConnStart(c)

	for {
		select {
		case <-c.ExitBuffChann:
			return
		}
	}
}

//停止连接
func (c *Connection) Stop() {
	if c.isClosed == true {
		return
	}

	c.isClosed = true
	//这里处理一些关闭回调业务
	c.TcpServer.CallOnConnStop(c)

	//关闭sock
	c.Conn.Close()

	//通知从缓冲队列读取数据的业务，该连接已关闭
	c.ExitBuffChann <- true

	close(c.ExitBuffChann)

	c.TcpServer.GetConnMgr().Remove(c)
	close(c.msgBuffChan)
	close(c.msgChan)
}

//从当前获取原始socket
func (c *Connection) GetTCPConnection() *net.TCPConn {
	return c.Conn
}

//获取当前id
func (c *Connection) GetConnID() uint32 {
	return c.ConnID
}

//获取远程客户端地址信息
func (c *Connection) RemoteAddr() net.Addr {
	return c.Conn.RemoteAddr()
}

func (c *Connection) SendMsg(msgId uint32, data []byte) error {
	if c.isClosed == true {
		return errors.New("connection closed whend send msg")
	}

	dp := NewDataPack()
	msg, err := dp.Pack(NewMsgPackage(msgId, data))
	if err != nil {
		fmt.Println("pack err msg id=", msgId)
		return errors.New("pack msg error")
	}
	c.msgChan <- msg

	return nil
}

func (c *Connection) SendBuffMsg(msgId uint32, data []byte) error {
	if c.isClosed == true {
		return errors.New("connection closed whend send msg")
	}

	dp := NewDataPack()
	msg, err := dp.Pack(NewMsgPackage(msgId, data))
	if err != nil {
		fmt.Println("pack err msg id=", msgId)
		return errors.New("pack msg error")
	}
	c.msgBuffChan <- msg

	return nil
}

//设置链接属性
func (c *Connection) SetProperty(key string, value interface{}) {
	c.propertyLock.Lock()
	defer c.propertyLock.Unlock()

	c.property[key] = value
}

//获取链接属性
func (c *Connection) GetProperty(key string) (interface{}, error) {
	c.propertyLock.RLock()
	defer c.propertyLock.RUnlock()

	if value, ok := c.property[key]; ok {
		return value, nil
	} else {
		return nil, errors.New("no property found")
	}
}

//移除链接属性
func (c *Connection) RemoveProperty(key string) {
	c.propertyLock.Lock()
	defer c.propertyLock.Unlock()

	delete(c.property, key)
}
